package com.scratch.gateway.filter;


import com.scratch.common.core.constant.basic.HttpConstants;
import com.scratch.common.core.utils.DateUtil;
import com.scratch.common.core.utils.core.StrUtil;
import com.scratch.common.core.utils.servlet.ServletUtil;
import com.scratch.common.core.utils.SignUtil;
import com.scratch.gateway.config.properties.ApiUrlsProperties;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 签名安全性验证
 */
@Component
@Slf4j
public class SignFilter implements GlobalFilter, Ordered {

    @Autowired
    private  ApiUrlsProperties apiUrls;

    public SignFilter(ApiUrlsProperties apiUrls) {
        this.apiUrls = apiUrls;
    }

    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String url = exchange.getRequest().getURI().getPath();
        //只验证后端服务接口
        if (!StrUtil.matches(url, apiUrls.getUrls())) {
            return chain.filter(exchange);
        }
        HttpHeaders httpHeaders=exchange.getRequest().getHeaders();
        String method = exchange.getRequest().getMethod().name();
        if (!HttpMethod.POST.name().equalsIgnoreCase(method)) {
            log.error("[签名处理]请求路径:{},{}", exchange.getRequest().getPath(), HttpConstants.Status.BAD_METHOD.getInfo());
            return ServletUtil.webFluxResponseWriter(exchange.getResponse(), HttpConstants.Status.BAD_METHOD.getCode());
        }
        if (!isJsonRequest(exchange)) {
            log.error("[签名处理]请求路径:{},{}", exchange.getRequest().getPath(), HttpConstants.Status.UNSUPPORTED_TYPE.getInfo());
            return ServletUtil.webFluxResponseWriter(exchange.getResponse(), HttpConstants.Status.UNSUPPORTED_TYPE.getCode());
        }
        String sign = httpHeaders.getFirst("sign");
        String appKey= httpHeaders.getFirst("appKey");
        String timestamp= httpHeaders.getFirst("timestamp");
        String path=httpHeaders.getFirst("path");
        if (!StringUtils.isBlank(appKey) && !StringUtils.isBlank(sign) && !StringUtils.isBlank(timestamp)) {
            LocalDateTime start = DateUtil.formatLocalDateTimeFromTimestampBySystemTimezone(Long.parseLong(timestamp));
            LocalDateTime now = LocalDateTime.now();
            long between = DateUtil.acquireMinutesBetween(start, now);
            if( between > (long)apiUrls.getDelay()){
                return ServletUtil.webFluxResponseWriter(exchange.getResponse(), HttpStatus.OK, HttpConstants.Status.SIGN.getInfo()+":签名时间戳已超过"+apiUrls.getDelay()+"分钟！", HttpConstants.Status.SIGN.getCode());
            }
        }else{
            log.error("[签名处理]请求路径:{},{}", exchange.getRequest().getPath(), HttpConstants.Status.UNSUPPORTED_TYPE.getInfo());
            return ServletUtil.webFluxResponseWriter(exchange.getResponse(), HttpConstants.Status.SIGN.getCode());
        }
        if(StringUtils.isBlank(path)||!exchange.getRequest().getPath().toString().equals(path)){
            return ServletUtil.webFluxResponseWriter(exchange.getResponse(), HttpStatus.OK, HttpConstants.Status.SIGN.getInfo()+":您尚未配置正确的签名路径！", HttpConstants.Status.SIGN.getCode());
        }
        boolean match = Objects.equals(SignUtil.generateSign(this.apiUrls.getAppSecret(), this.buildParamsMap(timestamp,path)), sign);
        if (!match) {
            return ServletUtil.webFluxResponseWriter(exchange.getResponse(), HttpStatus.OK, HttpConstants.Status.SIGN.getInfo(), HttpConstants.Status.SIGN.getCode());
        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE - 10;
    }


    /**
     * 是否是Json请求
     *
     * @param exchange HTTP请求
     */
    public boolean isJsonRequest(ServerWebExchange exchange) {
        String header = exchange.getRequest().getHeaders().getFirst(HttpHeaders.CONTENT_TYPE);
        return StrUtil.startWithIgnoreCase(header, MediaType.APPLICATION_JSON_VALUE);
    }

    private Map<String, String> buildParamsMap(String timestamp,String path) {
        Map<String, String> map = new HashMap<>();
        map.put("timestamp", timestamp);
        map.put("path", path);
        map.put("version", "v1");
        return map;
    }


}
